1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.util.system; 12 13 import hip.util.conv; 14 import hip.util.string:fromStringz, toStringz; 15 import hip.util.path:pathSeparator; 16 17 version(PSVita) version = NoSharedLibrarySupport; 18 version(WebAssembly) version = NoSharedLibrarySupport; 19 version(CustomRuntimeTest) version = NoSharedLibrarySupport; 20 21 debug version(Windows) 22 { 23 pragma(lib, "psapi.lib"); 24 pragma(lib, "dbghelp.lib"); 25 private struct MODLOAD_DATA {DWORD ssize; DWORD ssig; PVOID data; DWORD size; DWORD flags; } 26 import core.sys.windows.windef; 27 extern(Windows) private 28 { 29 alias SymUnloadModule = SymUnloadModule64; 30 BOOL SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); 31 DWORD64 SymLoadModuleEx( 32 HANDLE hProcess, 33 HANDLE hFile, 34 PCSTR ImageName, 35 PCSTR ModuleName, 36 DWORD64 BaseOfDll, 37 DWORD DllSize, 38 MODLOAD_DATA* Data, 39 DWORD Flags 40 ); 41 } 42 } 43 enum debugger = "asm {int 3;}"; 44 45 char[] sanitizePath(string path) @safe pure nothrow 46 { 47 char[] ret = new char[](path.length); 48 49 foreach(i, c; path) 50 { 51 version(Windows) 52 { 53 if(c == '/') 54 ret[i] = '\\'; 55 else 56 ret[i] = c; 57 } 58 else 59 { 60 if(c == '\\') 61 ret[i] = '/'; 62 else 63 ret[i] = c; 64 } 65 } 66 return ret; 67 } 68 bool isPathUnixStyle(string path) @safe pure nothrow 69 { 70 for(size_t i = 0; i < path.length; i++) 71 if(path[i] == '/') 72 return true; 73 return false; 74 } 75 string buildPath(string[] args...) @safe pure nothrow 76 { 77 if(args.length == 0) 78 return null; 79 string ret; 80 for(int i = 0; i < cast(int)args.length-1; i++) 81 ret~= args[i]~pathSeparator; 82 return ret~args[$-1]; 83 } 84 85 version(Windows) 86 { 87 // import core.sys.windows.winbase; 88 // import core.sys.windows.windef; 89 90 import hip.util.windows; 91 92 private HMODULE moduleHandle; 93 extern(Windows) nothrow @system void* dll_import_var(string name) 94 { 95 if(moduleHandle == null) 96 moduleHandle = GetModuleHandle(null); 97 return GetProcAddress(moduleHandle, (name~"\0").ptr); 98 } 99 string[] dllImportVariables(Args...)() 100 { 101 import std.traits:isFunctionPointer; 102 string[] failedFunctions; 103 static foreach(a; Args) 104 { 105 static assert(isFunctionPointer!a, "Can't dll import a non function pointer ( "~a.stringof~" )"); 106 a = cast(typeof(a))dll_import_var(a.stringof); 107 if(a is null) 108 failedFunctions~= a.stringof; 109 } 110 return failedFunctions; 111 } 112 113 string getWindowsErrorMessage(HRESULT hr) 114 { 115 wchar* buffer; 116 HRESULT fmt = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 117 FORMAT_MESSAGE_IGNORE_INSERTS | 118 FORMAT_MESSAGE_ALLOCATE_BUFFER, 119 null, hr, 0u, cast(LPWSTR)&buffer, 0, null); 120 121 if(fmt == 0) 122 return "Error code '"~hip.util.conv.toString(hr)~"' not found"; 123 string ret = fromUTF16(cast(wstring)buffer[0..fmt]); 124 125 LocalFree(buffer); 126 127 return ret; 128 } 129 130 void winEnforce(scope BOOL delegate() dg, scope string message) 131 { 132 if(!dg()) 133 throw new Error(message~": "~getWindowsErrorMessage(GetLastError())); 134 } 135 } 136 137 138 string dynamicLibraryGetLibName(string libName) 139 { 140 version(NoSharedLibrarySupport) return ""; 141 else version(Windows) return libName~".dll"; 142 else version(Posix) 143 { 144 import hip.util.path; 145 libName.filename = "lib"~libName.filename~".so"; 146 return libName; 147 } 148 else static assert(0, "Platform not supported"); 149 } 150 151 bool dynamicLibraryIsLibNameValid(string libName) 152 { 153 version(NoSharedLibrarySupport) 154 return true; 155 else version(Windows) 156 return libName[$-4..$] == ".dll"; 157 else version(Posix) 158 { 159 import hip.util.path; 160 return libName.filename[0..3] == "lib" && libName[$-3..$] == ".so"; 161 } 162 } 163 164 ///It will open the current executable if libName == null 165 void* dynamicLibraryLoad(string libName) 166 { 167 void* ret; 168 if(libName == null) 169 { 170 version(NoSharedLibrarySupport) 171 ret = null; 172 else version(Windows) 173 { 174 ret = GetModuleHandle(null); 175 } 176 else version(Posix) 177 { 178 import core.sys.posix.dlfcn : dlopen, RTLD_NOW; 179 ret = dlopen(null, RTLD_NOW); 180 } 181 } 182 else 183 { 184 version(NoSharedLibrarySupport) 185 ret = null; 186 else version(Android) 187 { 188 import core.sys.posix.dlfcn : dlopen, RTLD_LAZY; 189 ret = dlopen(libName.toStringz, RTLD_LAZY); 190 } 191 else version(Windows) 192 { 193 import core.runtime; 194 ret = Runtime.loadLibrary(libName); 195 debug 196 { 197 import core.sys.windows.psapi; 198 import core.sys.windows.winbase; 199 MODULEINFO moduleInfo; 200 winEnforce(() => GetModuleInformation(GetCurrentProcess(), ret, &moduleInfo, MODULEINFO.sizeof), "Could not get module information"); 201 if (!SymLoadModuleEx(GetCurrentProcess(), null, (libName~'\0').ptr, null, cast(ulong)moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage, null, 0)) 202 { 203 throw new Error("Failed to load the DLL named "~libName~" pdb symbols"); 204 } 205 206 } 207 } 208 else version(Posix) 209 { 210 import core.sys.posix.dlfcn : dlopen, RTLD_LAZY; 211 ret = dlopen(libName.toStringz, RTLD_LAZY); 212 } 213 } 214 return ret; 215 } 216 217 version(Windows) private const (char)* err; 218 void* dynamicLibrarySymbolLink(void* dll, const (char)* symbolName) 219 { 220 void* ret; 221 version(NoSharedLibrarySupport) 222 ret = null; 223 else version(Windows) 224 { 225 ret = GetProcAddress(dll, symbolName); 226 if(!ret) 227 err = ("Could not link symbol "~symbolName.fromStringz).ptr; 228 } 229 else version(Posix) 230 { 231 import core.sys.posix.dlfcn : dlsym; 232 ret = dlsym(dll, symbolName); 233 } 234 return ret; 235 } 236 237 238 string dynamicLibraryError() 239 { 240 version(NoSharedLibrarySupport) 241 return "Current platform does not load dynamic libraries"; 242 else version(Windows) 243 { 244 const(char)* ret = err; 245 err = null; 246 return cast(string)fromStringz(ret); 247 } 248 else version(Posix) 249 { 250 import core.sys.posix.dlfcn; 251 return cast(string)fromStringz(dlerror()); 252 } 253 else static assert(0, "Platform not supported"); 254 } 255 256 bool dynamicLibraryRelease(void* dll) 257 { 258 version(NoSharedLibrarySupport) 259 return false; 260 else version(UWP) 261 { 262 return cast(bool)FreeLibrary(dll); 263 } 264 else version(Android) 265 { 266 import core.sys.posix.dlfcn:dlclose; 267 return cast(bool)dlclose(dll); 268 } 269 else version(Posix) 270 { 271 import core.sys.posix.dlfcn:dlclose; 272 return cast(bool)dlclose(dll); 273 } 274 else 275 { 276 import core.runtime; 277 debug version(Windows) 278 { 279 import core.sys.windows.winbase; 280 import core.sys.windows.psapi; 281 MODULEINFO moduleInfo; 282 winEnforce(() => GetModuleInformation(GetCurrentProcess(), dll, &moduleInfo, MODULEINFO.sizeof), "Could not get module information"); 283 winEnforce(() => SymUnloadModule(GetCurrentProcess(), cast(ulong)moduleInfo.lpBaseOfDll), "Could not unload PDB"); 284 } 285 return Runtime.unloadLibrary(dll); 286 } 287 }